package com.zlyx.easy.access.abstracts;

import java.lang.reflect.Method;
import java.util.Collection;

import com.zlyx.easy.access.defaults.annotations.Delete;
import com.zlyx.easy.access.defaults.annotations.Insert;
import com.zlyx.easy.access.defaults.annotations.SQL;
import com.zlyx.easy.access.defaults.annotations.SQLProvider;
import com.zlyx.easy.access.defaults.annotations.Select;
import com.zlyx.easy.access.defaults.annotations.Update;
import com.zlyx.easy.access.interceptors.SqlInterceptor;
import com.zlyx.easy.access.supports.SqlCreater;
import com.zlyx.easy.core.loggers.Logger;
import com.zlyx.easy.core.map.EasyMap;
import com.zlyx.easy.core.spring.SpringUtils;
import com.zlyx.easy.core.utils.ClassUtils;
import com.zlyx.easy.core.utils.MethodUtils;
import com.zlyx.easy.core.utils.ObjectUtils;
import com.zlyx.easy.database.enums.SqlType;

/**
 * @Auth 赵光
 * @Describle
 * @2019年1月12日 下午12:36:06
 */
public abstract class AbstractSqlAssembler {

	protected Method method;

	protected SqlType type;

	protected String sql;

	public AbstractSqlAssembler(Class<?> tClass, Method method, Object[] args) throws Exception {
		EasyMap<String, Object> params = MethodUtils.getParamsMap(method, args);
		if (ObjectUtils.isNotEmpty(method.getAnnotation(Select.class))) {
			this.sql = assemble(params, method.getAnnotation(Select.class).value());
			this.type = SqlType.Select;
		} else if (ObjectUtils.isNotEmpty(method.getAnnotation(Delete.class))) {
			this.sql = assemble(params, method.getAnnotation(Delete.class).value());
			this.type = SqlType.Delete;
		} else if (ObjectUtils.isNotEmpty(method.getAnnotation(Update.class))) {
			this.sql = assemble(params, method.getAnnotation(Update.class).value());
			this.type = SqlType.Update;
		} else if (ObjectUtils.isNotEmpty(method.getAnnotation(Insert.class))) {
			this.sql = assemble(params, method.getAnnotation(Insert.class).value());
			this.type = SqlType.Insert;
		} else if (ObjectUtils.isNotEmpty(method.getAnnotation(SQLProvider.class))) {
			this.sql = assemble(params, getSql(method, args));
			this.type = SqlType.Select;
		} else if (ObjectUtils.isNotEmpty(method.getAnnotation(SQL.class))) {
			SQL sqlAnno = method.getAnnotation(SQL.class);
			this.sql = assemble(params, sqlAnno.value());
			this.type = sqlAnno.sqlType();
		}
		if (AbstractAccesser.class == method.getDeclaringClass()) {
			this.sql = SqlCreater.create(tClass, method, params, type);
		}
		this.method = method;
		this.doInterceptor(method, args);
		Logger.debug(method.getDeclaringClass(), "AcesserSQL日志@" + sql);
	}

	/**
	 * 从sql提供器获取sql
	 * 
	 * @param method
	 * @param args
	 * @return
	 * @throws Exception
	 */
	private String getSql(Method method, Object[] args) throws Exception {
		SQLProvider sqlProvider = method.getAnnotation(SQLProvider.class);
		Object obj = ClassUtils.newInstance(sqlProvider.type());
		Method sqlMethod = sqlProvider.type().getMethod(sqlProvider.method(), method.getParameterTypes());
		sqlMethod.setAccessible(true);
		return (String) sqlMethod.invoke(obj, args);
	}

	/**
	 * 执行自定义拦截器
	 * 
	 * @param method
	 * @param sql
	 * @return
	 */
	private AbstractSqlAssembler doInterceptor(Method method, Object[] args) {
		Collection<SqlInterceptor> interceptors = SpringUtils.getBeansOfType(SqlInterceptor.class).values();
		if (ObjectUtils.isNotEmpty(interceptors) && interceptors.size() != 0) {
			String sql = null;
			for (SqlInterceptor interceptor : interceptors) {
				sql = interceptor.doInterceptor(method, sql);
				if (sql != null) {
					this.sql = sql;
				}
			}
		}
		return this;
	}

	/**
	 * 编译sql(用户可以自定义编译方法)
	 * 
	 * @param params
	 * @param sql
	 * @return
	 */
	public abstract String assemble(EasyMap<String, Object> paramsMap, String sql);

	public SqlType getType() {
		return type;
	}

	public String getSql() {
		return sql;
	}

	public Method getMethod() {
		return method;
	}
}
